package websocket

import (
	"context"
	"encoding/json"
	"net/http"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"go.uber.org/zap"
)

// Manager WebSocket管理器
type Manager struct {
	clients     map[*Client]bool            // 客户端连接映射
	broadcast   chan []byte                 // 广播消息通道
	register    chan *Client                // 注册客户端通道
	unregister  chan *Client                // 注销客户端通道
	groups      map[string]map[*Client]bool // 分组映射
	groupMutex  sync.RWMutex                // 分组读写锁
	clientMutex sync.RWMutex                // 客户端读写锁
}

// Client WebSocket客户端
type Client struct {
	manager  *Manager               // 管理器
	conn     *websocket.Conn        // WebSocket连接
	send     chan []byte            // 发送消息通道
	id       string                 // 客户端ID
	groups   []string               // 所属分组
	metadata map[string]interface{} // 元数据
	ctx      context.Context        // 上下文
	cancel   context.CancelFunc     // 取消函数
}

// Message WebSocket消息
type Message struct {
	Type    string      `json:"type"`               // 消息类型
	Content interface{} `json:"content"`            // 消息内容
	From    string      `json:"from"`               // 消息来源
	To      string      `json:"to"`                 // 消息目标
	GroupID string      `json:"group_id,omitempty"` // 分组ID
}

// Config WebSocket配置
type Config struct {
	Path              string        // WebSocket路径
	MaxMessageSize    int64         // 最大消息大小
	WriteWait         time.Duration // 写入等待时间
	PongWait          time.Duration // Pong等待时间
	PingPeriod        time.Duration // Ping周期
	ReadBufferSize    int           // 读缓冲区大小
	WriteBufferSize   int           // 写缓冲区大小
	EnableCompression bool          // 是否启用压缩
}

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin: func(r *http.Request) bool {
		return true // 允许所有来源，生产环境应该限制
	},
}

// NewManager 创建WebSocket管理器
func NewManager() *Manager {
	return &Manager{
		clients:    make(map[*Client]bool),
		broadcast:  make(chan []byte),
		register:   make(chan *Client),
		unregister: make(chan *Client),
		groups:     make(map[string]map[*Client]bool),
	}
}

// Start 启动WebSocket管理器
func (m *Manager) Start() {
	go m.run()
}

// run WebSocket管理器运行
func (m *Manager) run() {
	for {
		select {
		case client := <-m.register:
			m.clientMutex.Lock()
			m.clients[client] = true
			m.clientMutex.Unlock()
			zap.L().Debug("WebSocket客户端已注册", zap.String("id", client.id))

		case client := <-m.unregister:
			if _, ok := m.clients[client]; ok {
				m.clientMutex.Lock()
				delete(m.clients, client)
				close(client.send)
				m.clientMutex.Unlock()

				// 从所有分组中移除
				m.groupMutex.Lock()
				for _, groupID := range client.groups {
					if group, exists := m.groups[groupID]; exists {
						delete(group, client)
						// 如果分组为空，则删除分组
						if len(group) == 0 {
							delete(m.groups, groupID)
						}
					}
				}
				m.groupMutex.Unlock()

				zap.L().Debug("WebSocket客户端已注销", zap.String("id", client.id))
			}

		case message := <-m.broadcast:
			m.clientMutex.RLock()
			for client := range m.clients {
				select {
				case client.send <- message:
				default:
					close(client.send)
					m.clientMutex.RUnlock()
					m.clientMutex.Lock()
					delete(m.clients, client)
					m.clientMutex.Unlock()
					m.clientMutex.RLock()
				}
			}
			m.clientMutex.RUnlock()
		}
	}
}

// ServeWs 处理WebSocket请求
func (m *Manager) ServeWs(c *gin.Context) {
	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		zap.L().Error("升级WebSocket连接失败", zap.Error(err))
		return
	}

	clientID := c.Query("client_id")
	if clientID == "" {
		clientID = c.GetString("user_id") // 尝试从上下文获取用户ID
		if clientID == "" {
			clientID = c.ClientIP() + "_" + time.Now().String() // 生成临时ID
		}
	}

	ctx, cancel := context.WithCancel(context.Background())
	client := &Client{
		manager:  m,
		conn:     conn,
		send:     make(chan []byte, 256),
		id:       clientID,
		groups:   []string{},
		metadata: make(map[string]interface{}),
		ctx:      ctx,
		cancel:   cancel,
	}

	m.register <- client

	// 允许收集垃圾
	go client.writePump()
	go client.readPump()
}

// readPump 从WebSocket连接读取数据
func (c *Client) readPump() {
	defer func() {
		c.manager.unregister <- c
		c.cancel()
		c.conn.Close()
	}()

	c.conn.SetReadLimit(1024 * 1024) // 1MB
	c.conn.SetReadDeadline(time.Now().Add(60 * time.Second))
	c.conn.SetPongHandler(func(string) error {
		c.conn.SetReadDeadline(time.Now().Add(60 * time.Second))
		return nil
	})

	for {
		_, message, err := c.conn.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				zap.L().Error("WebSocket读取错误", zap.Error(err))
			}
			break
		}

		// 处理接收到的消息
		c.handleMessage(message)
	}
}

// writePump 向WebSocket连接写入数据
func (c *Client) writePump() {
	ticker := time.NewTicker(54 * time.Second)
	defer func() {
		ticker.Stop()
		c.conn.Close()
	}()

	for {
		select {
		case message, ok := <-c.send:
			c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if !ok {
				// 通道已关闭
				c.conn.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}

			w, err := c.conn.NextWriter(websocket.TextMessage)
			if err != nil {
				return
			}
			w.Write(message)

			// 添加队列中的消息
			n := len(c.send)
			for i := 0; i < n; i++ {
				w.Write([]byte{'\n'})
				w.Write(<-c.send)
			}

			if err := w.Close(); err != nil {
				return
			}
		case <-ticker.C:
			c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
				return
			}
		case <-c.ctx.Done():
			return
		}
	}
}

// handleMessage 处理接收到的消息
func (c *Client) handleMessage(data []byte) {
	var msg Message
	if err := json.Unmarshal(data, &msg); err != nil {
		zap.L().Error("解析WebSocket消息失败", zap.Error(err), zap.ByteString("data", data))
		return
	}

	switch msg.Type {
	case "join_group":
		// 加入分组
		if groupID, ok := msg.Content.(string); ok {
			c.joinGroup(groupID)
		}
	case "leave_group":
		// 离开分组
		if groupID, ok := msg.Content.(string); ok {
			c.leaveGroup(groupID)
		}
	case "group_message":
		// 发送分组消息
		if msg.GroupID != "" {
			c.sendGroupMessage(msg.GroupID, data)
		}
	case "private_message":
		// 发送私人消息
		if msg.To != "" {
			c.sendPrivateMessage(msg.To, data)
		}
	case "broadcast":
		// 广播消息
		c.manager.broadcast <- data
	default:
		// 默认处理
		c.manager.broadcast <- data
	}
}

// joinGroup 加入分组
func (c *Client) joinGroup(groupID string) {
	c.manager.groupMutex.Lock()
	defer c.manager.groupMutex.Unlock()

	// 检查分组是否存在，不存在则创建
	if _, exists := c.manager.groups[groupID]; !exists {
		c.manager.groups[groupID] = make(map[*Client]bool)
	}

	// 将客户端加入分组
	c.manager.groups[groupID][c] = true

	// 更新客户端的分组列表
	for _, g := range c.groups {
		if g == groupID {
			return // 已在分组中
		}
	}
	c.groups = append(c.groups, groupID)

	zap.L().Debug("客户端加入分组", zap.String("client_id", c.id), zap.String("group_id", groupID))
}

// leaveGroup 离开分组
func (c *Client) leaveGroup(groupID string) {
	c.manager.groupMutex.Lock()
	defer c.manager.groupMutex.Unlock()

	// 从分组中移除客户端
	if group, exists := c.manager.groups[groupID]; exists {
		delete(group, c)

		// 如果分组为空，则删除分组
		if len(group) == 0 {
			delete(c.manager.groups, groupID)
		}
	}

	// 更新客户端的分组列表
	for i, g := range c.groups {
		if g == groupID {
			c.groups = append(c.groups[:i], c.groups[i+1:]...)
			break
		}
	}

	zap.L().Debug("客户端离开分组", zap.String("client_id", c.id), zap.String("group_id", groupID))
}

// sendGroupMessage 发送分组消息
func (c *Client) sendGroupMessage(groupID string, message []byte) {
	c.manager.groupMutex.RLock()
	defer c.manager.groupMutex.RUnlock()

	if group, exists := c.manager.groups[groupID]; exists {
		for client := range group {
			select {
			case client.send <- message:
			default:
				close(client.send)
				delete(group, client)
			}
		}
	}
}

// sendPrivateMessage 发送私人消息
func (c *Client) sendPrivateMessage(targetID string, message []byte) {
	c.manager.clientMutex.RLock()
	defer c.manager.clientMutex.RUnlock()

	for client := range c.manager.clients {
		if client.id == targetID {
			select {
			case client.send <- message:
				return
			default:
				close(client.send)
				delete(c.manager.clients, client)
			}
		}
	}
}

// BroadcastMessage 广播消息
func (m *Manager) BroadcastMessage(message interface{}) {
	data, err := json.Marshal(message)
	if err != nil {
		zap.L().Error("序列化消息失败", zap.Error(err))
		return
	}

	m.broadcast <- data
}

// SendToGroup 发送消息到分组
func (m *Manager) SendToGroup(groupID string, message interface{}) {
	data, err := json.Marshal(message)
	if err != nil {
		zap.L().Error("序列化消息失败", zap.Error(err))
		return
	}

	m.groupMutex.RLock()
	defer m.groupMutex.RUnlock()

	if group, exists := m.groups[groupID]; exists {
		for client := range group {
			select {
			case client.send <- data:
			default:
				close(client.send)
				delete(group, client)
			}
		}
	}
}

// SendToClient 发送消息到客户端
func (m *Manager) SendToClient(clientID string, message interface{}) {
	data, err := json.Marshal(message)
	if err != nil {
		zap.L().Error("序列化消息失败", zap.Error(err))
		return
	}

	m.clientMutex.RLock()
	defer m.clientMutex.RUnlock()

	for client := range m.clients {
		if client.id == clientID {
			select {
			case client.send <- data:
				return
			default:
				close(client.send)
				delete(m.clients, client)
			}
		}
	}
}

// GetClientCount 获取客户端数量
func (m *Manager) GetClientCount() int {
	m.clientMutex.RLock()
	defer m.clientMutex.RUnlock()
	return len(m.clients)
}

// GetGroupCount 获取分组数量
func (m *Manager) GetGroupCount() int {
	m.groupMutex.RLock()
	defer m.groupMutex.RUnlock()
	return len(m.groups)
}

// GetGroupClientCount 获取分组客户端数量
func (m *Manager) GetGroupClientCount(groupID string) int {
	m.groupMutex.RLock()
	defer m.groupMutex.RUnlock()

	if group, exists := m.groups[groupID]; exists {
		return len(group)
	}
	return 0
}
